
#include "StdAfx.h"
#include ".\mixer.h"

#pragma comment(lib, "winmm")

#define	WND_CLASS_NAME	_T("Mixer Msg Wnd Class")
#define	WND_NAME		_T("Mixer Msg Wnd")


CMixer * CMixer::m_pMixerArray[MAX_MIXER_COUNT] = {0};

CMixer::CMixer(UINT uMxID)
	: m_hMixer(NULL)
	, m_uMixerID(uMxID)
	, m_nRefCount(0)
	, m_hWnd(NULL)
{
}

CMixer::~CMixer(void)
{
}

CMixer * CMixer::OpenMixer(UINT uMxID)
{
    UINT n = min(mixerGetNumDevs(), MAX_MIXER_COUNT);
	CMixer *pMixer = NULL;

	if(uMxID < n)
	{
		pMixer = m_pMixerArray[uMxID];
		if(pMixer == NULL)
		{
			pMixer = new CMixer(uMxID);
			if(pMixer->Init())
			{
				m_pMixerArray[uMxID] = pMixer;
			}
			else
			{
				delete pMixer;
				pMixer = NULL;
			}
		}
	}

	if(pMixer)
		pMixer->m_nRefCount++;

	return pMixer;
}

void CMixer::CloseMixer()
{
	m_nRefCount--;
	if(m_nRefCount == 0)
	{
		mixerClose(m_hMixer);
		DestroyWindow(m_hWnd);

		m_pMixerArray[m_uMixerID] = NULL;
		delete this;
	}
}

bool CMixer::Init()
{
	WNDCLASSEX wcx = {0};
	wcx.cbSize = sizeof(WNDCLASSEX);
	wcx.lpszClassName = WND_CLASS_NAME;
	wcx.lpfnWndProc = (WNDPROC)MixerWndProc;

	::RegisterClassEx(&wcx);
	m_hWnd = CreateWindow(	WND_CLASS_NAME,
							WND_NAME,
							WS_POPUP | WS_DISABLED,
							0, 0, 0, 0,
							NULL, NULL, NULL, NULL );
	if ( !m_hWnd )
	{
		return false;
	}
	SetWindowLong(m_hWnd, GWL_USERDATA, (LONG)this);
	::ShowWindow(m_hWnd, SW_HIDE);

	MMRESULT mmResult;

	mmResult = mixerOpen(&m_hMixer, m_uMixerID, (DWORD)m_hWnd, 0L, CALLBACK_WINDOW );
	if ( mmResult != MMSYSERR_NOERROR )
	{
		::DestroyWindow( m_hWnd );
		return false;
	}
   
	return true;
}

LRESULT CALLBACK CMixer::MixerWndProc( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
{
	CMixer *pThis = (CMixer *)GetWindowLong(hwnd, GWL_USERDATA);
	if(pThis)
	{
		pThis->OnMixerMessage(uMsg, wParam, lParam);
	}

	return ::DefWindowProc( hwnd, uMsg, wParam, lParam);
}

void CMixer::OnMixerMessage(UINT uMsg, WPARAM wParam, LPARAM lParam)
{
	POSITION pos = m_EventReceiverList.GetHeadPosition();
	while(pos)
	{
		CMixerEventReceiver *pReceiver = m_EventReceiverList.GetNext(pos);
        if(uMsg == MM_MIXM_CONTROL_CHANGE)
		{
			pReceiver->OnControlChanged(this, static_cast<DWORD>(lParam));
		}
	}
}

void CMixer::AddEventReceiver(CMixerEventReceiver *pReceiver)
{
	if(!m_EventReceiverList.Find(pReceiver))
	{
		m_EventReceiverList.AddTail(pReceiver);
	}
}

void CMixer::RemoveEventReceiver(CMixerEventReceiver *pReceiver)
{
	POSITION pos = m_EventReceiverList.Find(pReceiver);
	if(pos)
	{
		m_EventReceiverList.RemoveAt(pos);
	}
}
